/**
 * \file reception_linux.c
 * \author H4201
 */

/*MODULES USED*/

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <mqueue.h>
#include <pthread.h>
#include "reception_linux.h"
#include "mere.h"
#include "../reseau/reception.h"
#include "../reseau/connexion.h"
#include "../interface/messqueue.h"
#include "../erreur/erreurs.h"
#include "../interface/variablesglobales.h"
#include "../ChaineCond/mise_en_carton.h"
#include "../ChaineCond/mise_en_palette.h"
#include "../ChaineCond/init_functions.h"
#include "../ChaineCond/stockage.h"
#include "../ChaineCond/impression.h"

/*GLOBAL VARIABLES*/

/**
 * Identifiant du thread "Envoi Linux"
 */
static pthread_t envoi_linux_thread;

/*EXPORTED FUNCTIONS*/

/**
 * Fonction qui sert de point d'entré au thread "Reception Linux"
 * \param parameter inutilisé ici
 */
void* reception_linux (void *parameter) {
    int sockfd, numero_port;
    message_t message;
    
    mqd_t bal_retrait = mq_open(BAL_RETRAIT_NAME, O_WRONLY);
    mqd_t bal_messages = mq_open(BAL_MESSAGES_NAME, O_WRONLY);
    
    numero_port = (int) parameter;

    g_client_sockfd = ouvrir_connexion_supervision(numero_port, &sockfd);
    
    for (;;) {
        message = recevoir(g_client_sockfd);
        printf("type du message : %ld\n", message.type);
        if (message.type == INIT) {
            initialiser_application(message);
        } else if (message.type == ARRDEG) {
            fermer_clapet();
	    mq_send(bal_messages, (char *) &message, sizeof(message_t), 1);
        } else if (message.type == DEMRETRAIT) {
            mq_send(bal_retrait, (char *) &message, sizeof(message_t), 1);
        } else if (message.type == REPARERR) {    
	remplir_semaphore();
	mq_send(bal_messages, (char *) &message, sizeof(message_t), 1);
        } else if (message.type == REPRNORM) {
	    if (statut_semaphore()) {
		ouvrir_clapet();
		mq_send(bal_messages, (char *) &message, sizeof(message_t), 1);
	    }
        } else if (message.type == REPRSUPP) {
	    if (statut_semaphore()) {
		supprimer_carton_courant();
		ouvrir_clapet();
		mq_send(bal_messages, (char *) &message, sizeof(message_t), 1);
	    }
        } else if (message.type == STOPLOT) {
	    if (statut_semaphore()) {
		fermer_clapet();
		supprimer_carton_courant();
		vider_bal_impression();
		vider_bal_palettes();
		vider_bal_cartons();
		mq_send(bal_messages, (char *) &message, sizeof(message_t), 1);
	    }
        } else if (message.type == GO) {
	    if (statut_semaphore()) {
		demarrer_production(message.params[0]);
		mq_send(bal_messages, (char *) &message, sizeof(message_t), 1);
	    }
        } else if (message.type == ARRET || (message.type == -1 && message.params[0] == -1)) {
            break;
        }
    }
    
    arreter_application(sockfd);
    mq_close(bal_retrait);
    mq_close(bal_messages);

    pthread_exit(NULL);
}

/**
 * Lance la production d'un type de pièce.
 * \param type de pièce à lancer ( 0 = A; 1 = B)
 */
void demarrer_production(int type) {
    charger_lot(type);
    ouvrir_clapet();
}

/**
 * Initialise la chaine de production à partir du message d'initialisation envoyé par le superviseur.
 * \param message_init Message d'initialisation envoyé par le superviseur.
 */
void initialiser_application(message_t message_init) {
    mqd_t bal_messages = mq_open(BAL_MESSAGES_NAME, O_WRONLY);
    
    g_nb_pal_a = message_init.params[0]; // nombre de palettes à faire de a
    g_nb_cart_pal_a = message_init.params[1]; // nombre de cartons par palette de a
    g_nb_piec_cart_a = message_init.params[2]; // nombre de pièces par carton de a
    g_num_lot_a = message_init.params[3]; // numéro du lot de fabrication en cours de a
    g_dim_a = message_init.params[4]; // dimensions que doivent faire les a
    g_seuil_defect_a = message_init.params[5]; // seuil de pièces défectueuses de a, en partie par 10000
    g_nb_pal_b = message_init.params[6]; // nombre de palettes à faire de b
    g_nb_cart_pal_b = message_init.params[7]; // nombre de cartons par palettes de b
    g_nb_piec_cart_b = message_init.params[8]; // nombre de pièces par carton de b
    g_dim_b = message_init.params[9]; // dimensions que doivent faire les b
    g_num_lot_b = message_init.params[10]; // numéro du lot de fabrication en cours de b
    g_seuil_defect_b = message_init.params[11]; // seuil de pièces défectueuses de b, en partie par 10000
    g_code_op = message_init.params[12]; // code opérateur
        
    // Mise en place des globaux pour la mise en palette
    init_globaux_pal();
    
    mq_send(bal_messages, (char *) &message_init, sizeof(message_t), 100);
    envoi_linux_thread = lancer_thread_envoi();
    mq_close(bal_messages);
}

/**
 * Lance la procedure d'arret de l'application.
 * \param sockfd Socket Serveur
 */
void arreter_application(int sockfd) {
    fermer_clapet();
    
    message_t message_arret;
    message_arret.type = ARRET;
    
    demander_arret();
    
    mqd_t bal_retrait = mq_open(BAL_RETRAIT_NAME, O_WRONLY);
    mq_send(bal_retrait, (char *) &message_arret, sizeof(message_t), 1);
    mq_close(bal_retrait);
    
    pthread_join(envoi_linux_thread, NULL);
    join_all_threads();
    
    mqd_t bal_erreurs = mq_open(BAL_ERREURS_NAME, O_WRONLY);
    mq_send(bal_erreurs, (char *) &message_arret, sizeof(message_t), 1);
    mq_close(bal_erreurs);
    
    fermer_connexion_supervision(sockfd, g_client_sockfd);
}
